﻿using System;
using System.Collections.Generic;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Shapes;
using FarseerGames.FarseerPhysics.Mathematics;
using FreeGoo.GameEngine;
using FreeGoo.GameEngine.Renderables;
using FreeGoo.GameEngine.Renderables.Particles;
using FreeGoo.GameEngine.Renderables.Particles.Keys;
using FreeGoo.GameEngine.Renderables.Particles.States;
using FreeGoo.WpfRenderer.Constants;

namespace FreeGoo.WpfRenderer
{
    public class ParticleRenderer : ImageRenderer
    {
        private const float InflatedBallonSizeFactor = 1.5f;
        private const float SelectedNonDraggedParticle = 1.25f;
        private const float SelectedDraggedParticle = 1.1f;

        private IList<Line> _lines;

        public ParticleRenderer(RendererFactory factory, Particle particle)
            : base(factory, particle, GetImageForParticleType(factory, particle), Vector2.Zero)
        {
            AdjustImage();
            Update();
        }

        public Particle Particle { get { return Renderable as Particle; } }
        public Engine Engine { get { return Particle.Engine; } }

        public static Image GetImageForParticleType(RendererFactory factory, Particle particle)
        {
            Color color = RendererFactory.GetColorForLinkable(particle);

            string fileName = @"Resources\LargeGoo.png";

            if (particle.IsSelected)
            {
                fileName = @"Resources\LargeGooSelected.png";
                color =
                    Color.FromArgb(
                        0,
                        (byte)Math.Min(255, color.R * 6 / 5),
                        (byte)Math.Min(255, color.G * 6 / 5),
                        (byte)Math.Min(255, color.B * 6 / 5));
            }
            else if (particle.IsSleeping)
            {
                fileName = @"Resources\LargeGooSleeping.png";
                color =
                    Color.FromArgb(
                        0,
                        (byte)Math.Min(255, color.R * 4 / 5),
                        (byte)Math.Min(255, color.G * 4 / 5),
                        (byte)Math.Min(255, color.B * 4 / 5));
            }
            else if (particle.IsLinked && !particle.CanBeUnlinked)
            {
                fileName = @"Resources\LargeGooFixated.png";
                color =
                    Color.FromArgb(
                        0,
                        (byte)Math.Min(255, color.R * 4 / 5),
                        (byte)Math.Min(255, color.G * 4 / 5),
                        (byte)Math.Min(255, color.B * 4 / 5));
            }

            if (particle is Key)
            {
                fileName = @"Resources\Key.jpeg";
            }

            return factory.CreateImageForFileNameColorized(fileName, color);
        }

        public override void Update()
        {
            base.Update();

            DeleteOldLines();

            if (Particle.IsSelected)
            {
                if (Particle.State is Selected && !(Particle.State as Selected).DragStarted)
                {
                    ShowAboutToDragLines();
                }
                else
                {
                    ShowWouldConnectToLines();
                }
            }
        }

        public override void Delete()
        {
            base.Delete();
            DeleteOldLines();
        }

        public override void StateChanged()
        {
            Delete();
            if (!Particle.ScheduledForDelete)
            {
                Image = GetImageForParticleType(Factory, Particle);
                AdjustImage();
                SetCanvasContent(Image);
                Update();
            }
        }

        private void ShowAboutToDragLines()
        {
            _lines = new List<Line>();
            Line line = new Line();
            line.SetValue(Canvas.ZIndexProperty, 10);

            line.X1 = Particle.Body.Position.X;
            line.Y1 = Particle.Body.Position.Y;

            line.X2 = Engine.UserInputController.CursorPosition.X;
            line.Y2 = Engine.UserInputController.CursorPosition.Y;

            line.Stroke = BrushConstants.Black;
            line.StrokeThickness = 4;
            line.StrokeStartLineCap = PenLineCap.Round;

            _lines.Add(line);
            Factory.Canvas.Children.Add(line);
        }

        private void ShowWouldConnectToLines()
        {
            ParticleConnectionTestResult result = Particle.ParticleConnectionTest();

            if (result.ResultType == ParticleConnectionTestResultType.ListOfLinkedParticles)
            {
                _lines = new List<Line>();
                foreach (ILinkable linkable in result.WouldConnectTo)
                {
                    Line line = new Line();
                    line.SetValue(Canvas.ZIndexProperty, 3);

                    line.X1 = Particle.Body.Position.X;
                    line.Y1 = Particle.Body.Position.Y;

                    line.X2 = linkable.Position.X;
                    line.Y2 = linkable.Position.Y;

                    line.Stroke = BrushConstants.Silver;

                    _lines.Add(line);
                    Factory.Canvas.Children.Add(line);
                }
            }
            else if (result.ResultType == ParticleConnectionTestResultType.LinkTwoOtherParticles)
            {
                _lines = new List<Line>();
                Line line = new Line();
                line.SetValue(Canvas.ZIndexProperty, 3);

                line.X1 = result.FirstLinkable.Position.X;
                line.Y1 = result.FirstLinkable.Position.Y;

                line.X2 = result.SecondLinkable.Position.X;
                line.Y2 = result.SecondLinkable.Position.Y;

                line.Stroke = BrushConstants.Silver;
                line.StrokeThickness = 2;

                _lines.Add(line);
                Factory.Canvas.Children.Add(line);
            }
        }

        private void DeleteOldLines()
        {
            if (_lines != null)
            {
                foreach (Line line in _lines)
                {
                    Factory.Canvas.Children.Remove(line);
                }

                _lines = null;
            }
        }

        private void AdjustImage()
        {
            float sizeFactor = 1;
            if (Particle is Balloon && Particle.IsLinked)
            {
                sizeFactor = InflatedBallonSizeFactor;
            }
            else if (Particle.State is Selected)
            {
                if ((Particle.State as Selected).DragStarted)
                {
                    sizeFactor = SelectedDraggedParticle;
                }
                else
                {
                    sizeFactor = SelectedNonDraggedParticle;
                }
            }

            Image.Width = Particle.Radius * sizeFactor * 2;
            Image.Height = Particle.Radius * sizeFactor * 2;
            AdjustOffset();
            Image.SetValue(Canvas.ZIndexProperty, 4);
        }
    }
}
